package com.qd.p2p.web.action.additional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.Resource;

import com.alibaba.fastjson.JSONObject;
import com.qdlc.p2p.biz.service.AdditionalMovieTicketService;
import com.qdlc.p2p.biz.service.UserIdentifyService;
import com.qdlc.p2p.biz.service.UserService;
import com.qdlc.p2p.biz.task.ConcurrentUtil;
import com.qdlc.p2p.biz.tpp.TppBaseInterface;
import com.qdlc.p2p.biz.tpp.TppServiceFactory;
import com.qdlc.p2p.common.enums.EnumActicityPlanNid;
import com.qdlc.p2p.common.exception.AccountException;
import com.qdlc.p2p.common.exception.BorrowException;
import com.qdlc.p2p.common.exception.UserException;
import com.qdlc.p2p.common.util.*;
import com.qdlc.p2p.common.util.code.MD5;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.dao.AccountDao;
import com.qdlc.p2p.dal.dao.MovieConfigDao;
import com.qdlc.p2p.dal.dto.*;
import com.qdlc.p2p.dal.model.TppAccountModel;
import com.qdlc.p2p.dal.model.TppModel;
import com.qdlc.p2p.dal.util.UserUtils;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.log4j.Logger;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;

import com.opensymphony.xwork2.ModelDriven;
import com.qdlc.p2p.biz.service.AdditionalUserMovieTicketService;
import com.qdlc.p2p.biz.web.action.BaseAction;
import com.qdlc.p2p.dal.common.model.jpa.PageDataList;
import com.qdlc.p2p.dal.model.AdditionalUserMovieTicketModel;
import org.apache.struts2.convention.annotation.Result;

/**
 * Created by liaoxiangkai on 2015/11/25.
 */
public class UserMovieTicketAction extends BaseAction<AdditionalUserMovieTicketModel> implements ModelDriven<AdditionalUserMovieTicketModel>{

    private Logger logger = Logger.getLogger(UserMovieTicketAction.class);
    @Resource
    private AdditionalUserMovieTicketService additionalUserMovieTicketService;
    @Resource
    private AdditionalMovieTicketService additionalMovieTicketService;
    @Resource
    private UserService userService;
    @Resource
    private UserIdentifyService userIdentifyService;
    @Resource
    private MovieConfigDao movieConfigDao;

    private Map<String, Object> data;

    /**
     * 获取用户电影票列表
     *
     * @throws Exception
     */
    @Action(value = "/movieTicket/myMovieTicketList", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void myMovieTicketList() throws Exception {
        User user = getSessionUser();
        data = new HashMap<String, Object>();
        int pageNumber = paramInt("page"); // 当前页数
        int pageSize = paramInt("rows"); // 每页总数
        int status = paramInt("status"); //用户电影票状态
        if (pageSize <= 0) pageSize = 5;
        PageDataList<AdditionalUserMovieTicketModel> ticketList = additionalUserMovieTicketService.getUserMovieTicketList(user, pageNumber, pageSize, status,null);
        data.put("total", ticketList.getPage().getTotal()); // 总行数
        data.put("data", ticketList); // 集合对象
        data.put("status", status);
        printJson(getStringOfJpaObj(data));
    }

    @Action(value = "/movieTicket/movieTicketDetail", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void movieTicketDetail() throws Exception {
        User user = getSessionUser();
        if (null == user) {
            printWebResult("请先登录", false);
            return;
        }
        String exchangeCode = paramString("exchangeCode");
        AdditionalMovieTicket ticketDetail = additionalMovieTicketService.userTicketDetail(exchangeCode, user.getUserId());
        printJson(getStringOfJpaObj(ticketDetail));
    }

    /**
     * 用户兑换后异步返回通知
     */
    @Action(value = "/movieTicket/exchangeNotify")
    public void exchangeNotify() throws Exception {
        data = new ConcurrentHashMap<String, Object>();
        String exchangeCode = paramString("code_number"); //兑换码
        String userId = paramString("userid"); //用户id
        String movieName = paramString("movie"); //电影名
        String fetchCode = paramString("fetch_code");//取票码
        String fetchPhone = paramString("fetch_phone");//取票手机号码
        String cinema = paramString("cinema"); //电影院
        String scene = paramString("scene"); //具体放映时间+放映厅
        String seat = paramString("seat"); //观看位置
        String sign = paramString("sign");//签名
        logger.info(String.format("--->兑换异步通知开始：用户id[%s],兑换码[%s]", userId, exchangeCode));
        if (StringUtil.isBlank(userId) || StringUtil.isBlank(exchangeCode)) {
            logger.info("兑换异步通知错误：参数为空");
            data.put("code", "1");
            data.put("msg", "参数为空");
            printJson(getStringOfJpaObj(data));
            return;
        }
        if (!AdditionalUserMovieTicketModel.sign().equals(sign)) {
            logger.info("兑换异步通知错误：签名错误");
            data.put("code", "2");
            data.put("msg", "签名错误");
            printJson(getStringOfJpaObj(data));
            return;
        }
        User user = userService.find(Long.parseLong(userId));
        if (null == user) {
            logger.info("兑换异步通知错误：用户不存在id:" + userId);
            data.put("code", "5");
            data.put("msg", "用户不存在！");
            printJson(getStringOfJpaObj(data));
            return;
        }
        //修改用户电影票表状态
        int result = additionalUserMovieTicketService.updateByExchangeCode(Long.parseLong(userId),exchangeCode, AdditionalUserMovieTicketModel.USER_MOVIETICKE_USED);
        if (result <= 0) {
            logger.info("兑换异步通知错误：本地更新失败");
            data.put("code", "3");
            data.put("msg", "本地更新失败");
            printJson(getStringOfJpaObj(data));
            return;
        }
        //插入电影票详情表
        AdditionalMovieTicket additionalMovieTicket = new AdditionalMovieTicket();
        additionalMovieTicket.setUser(user);
        additionalMovieTicket.setExchangeCode(exchangeCode);
        additionalMovieTicket.setFetchPhone(fetchPhone);
        additionalMovieTicket.setMovieName(movieName);
        additionalMovieTicket.setFetchCode(fetchCode);
        additionalMovieTicket.setCinema(cinema);
        additionalMovieTicket.setScene(scene);
        additionalMovieTicket.setSeat(seat);
        additionalMovieTicket.setAddTime(DateUtil.getNow());
        additionalMovieTicket = additionalMovieTicketService.save(additionalMovieTicket);
        if (null != additionalMovieTicket) {
            logger.info("兑换异步通知结束：本地保存影院信息成功，返回code=99");
            data.put("code", "99");
            data.put("msg", "本地保存成功");
            printJson(getStringOfJpaObj(data));
        } else {
            logger.info("兑换异步通知结束：本地保存影院信息失败");
            data.put("code", "3");
            data.put("msg", "本地保存失败");
            printJson(getStringOfJpaObj(data));
        }
    }

    /**
     * 异步出票
     *  1.投标请求php接口(orderNo&userId)等待异步发送兑换码
     *  2.接收php异步发送的兑换码
     *  3.用户点击兑换，兑换成功后蜘蛛网异步回调
     */
    @Action(value = "/movieTicket/acceptExchangeCode")
    public void acceptExchangeCode() throws Exception {
        data = new ConcurrentHashMap<String, Object>();
        String exchangeCode = paramString("code_number");
        String partnerId = paramString("partners_id");
        String orderNo = paramString("order_no");
        String userId = paramString("userid");
        String sign = paramString("sign");
        logger.info(String.format("--->出票异步回调：{exchangeCode：%s,partnerId:%s,orderNo:%s,userId:%s,sign:%s}", exchangeCode, partnerId, orderNo, userId, sign));
        if (StringUtil.isBlank(userId) || StringUtil.isBlank(orderNo) || StringUtil.isBlank(exchangeCode) || StringUtil.isBlank(partnerId)) {
            data.put("code", "1");
            data.put("msg", "请求参数为空");
            printJson(getStringOfJpaObj(data));
            return;
        }
        if(!AdditionalUserMovieTicketModel.sign().equals(sign)){
            data.put("code", "2");
            data.put("msg", "签名错误");
            printJson(getStringOfJpaObj(data));
            return;
        };
        int result = additionalUserMovieTicketService.updateByOrderNo(orderNo, partnerId, exchangeCode, Long.parseLong(userId));
        if (result > 0) {
            logger.info("出票异步回调本地更新成功，返回成功code=99");
            data.put("code", "99"); //0：成功
            data.put("msg", "更新成功");
            printJson(getStringOfJpaObj(data));
        } else {
            logger.info("出票异步回调本地更新失败，返回code=3");
            data.put("code", "3");
            data.put("msg", "本地保存失败");
            printJson(getStringOfJpaObj(data));
        }
    }

    /**
     *  1.线下获得兑换券
     *  2.到平台兑换[php验证券号正确性，返回成功本地保存，告知php成功保存]
     *  3.到蜘蛛网兑换
     */
    @Action(value = "/movieTicket/offlineExchange", interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack")})
    public void offlineExchange() throws Exception {
        data = new HashMap<String, Object>();
        User user = getSessionUser();
        if (null == user) {
            printWebResult("请先登录！", false);
            return;
        }
        String exchangeCode = paramString("movie-ticket");
        if (StringUtil.isBlank(exchangeCode)) {
            printWebResult("兑换码不能为空！", false);
            return;
        }
        //线下兑换请求php验证，参数：code_number，channel_id，sign
        logger.info("--->线下兑换开始,兑换码：" + exchangeCode);
        NameValuePair[] exchangeData = new NameValuePair[]{new NameValuePair("code_number", exchangeCode)};
        String url = SystemConfigHelper.getValue(SystemConfigHelper.Nid.REQUEST_PHP_DOMAIN) + "/Film/codejudge.html";
        String result = AdditionalUserMovieTicketModel.requestPHP(url, exchangeData);
        logger.info("线下兑换验证兑换码返回结果：" + result);
        if (StringUtil.isBlank(result)) {
            printWebResult("兑换失败", false);
            return;
        }
        if (!"0".equals(JSONObject.parseObject(result).get("code"))) {
            printWebResult("兑换码不可用", false);
            return;
        }
        JSONObject jsonObject = (JSONObject) JSONObject.parseObject(result).get("data");
        String partnerId = jsonObject.getString("partners_id");
        if (null == partnerId) {
            printWebResult("兑换失败,请联系客服或重新兑换！", false);
            return;
        }
        AdditionalUserMovieTicket additionalUserMovieTicket = new AdditionalUserMovieTicket();
        additionalUserMovieTicket.setStatus(AdditionalUserMovieTicketModel.USER_MOVIETICKE_UNUSED);
        //保存赠送用户的电影票信息
        String orderNo = OrderNoUtil.getInstance().getSerialNumber(); //请求php流水号
        additionalUserMovieTicket.setUser(user);
        additionalUserMovieTicket.setCount(1);
        additionalUserMovieTicket.setExchangeCode(exchangeCode);
        additionalUserMovieTicket.setPartnerId(partnerId);
        additionalUserMovieTicket.setOrderNo(orderNo);
        additionalUserMovieTicket.setSourceType(EnumActicityPlanNid.OFFLINE_EXCHANGE_TICKET.getValue());
        additionalUserMovieTicket.setExpiredTime(DateUtil.rollDay(new Date(), 60));//TODO 兑换券的有效时间
        additionalUserMovieTicket.setAddTime(DateUtil.getNow());

        additionalUserMovieTicket =  additionalUserMovieTicketService.save(additionalUserMovieTicket);
        if (null != additionalUserMovieTicket) {
            //通知php本地保存成功，参数：partners_id，userid，mobile，orderNo订单号，code_number兑换码，sign签名
            NameValuePair[] saveSuccData = {new NameValuePair("mobile", user.getMobilePhone()), new NameValuePair("orderNo", orderNo),
                    new NameValuePair("userid", String.valueOf(user.getUserId())), new NameValuePair("partners_id", partnerId),
                    new NameValuePair("code_number",exchangeCode)};
            String u = SystemConfigHelper.getValue(SystemConfigHelper.Nid.REQUEST_PHP_DOMAIN) + "/Film/codestart.html";
            String saveResult = AdditionalUserMovieTicketModel.requestPHP(u, saveSuccData);
            logger.info("--->线下兑换本地保存成功，通知php返回结果：" + saveResult);
        }
        printWebResult("恭喜你，兑换成功！", true);
    }

    /**
     * 电影票详情JSON数据
     * @return
     *
     * @throws Exception
     */
    @Action(value = "/movieTicket/ticket", interceptorRefs = { @InterceptorRef("globalStack") })
    public String movieTickets() throws Exception {

        saveToken("buyMovieTicketsToken");
        String buyMovieTicketsToken = (String) session.get("buyMovieTicketsToken");

        String pId = paramString("id");// 电影ID
        User user = getSessionUser();
        long id = 0;

        // 是否登录和设置支付密码
        if (!StringUtil.isBlank(user)) {
            if (!StringUtil.isBlank(user.getPayPwd())) {
                request.setAttribute("isPayPwd",Boolean.TRUE);
            } else {
                request.setAttribute("isPayPwd",Boolean.FALSE);
            }
            request.setAttribute("isLogin",Boolean.TRUE);
        } else {
            request.setAttribute("isPayPwd",Boolean.TRUE);
            request.setAttribute("isLogin",Boolean.FALSE);
        }

        if (!StringUtil.isBlank(pId)) {
            if (pId.length() != 32) {
                logger.info("页面参数被恶意篡改，提示“对不起，您查看的页面不存在！”------"+pId);
                throw new BorrowException("对不起，您查看的页面不存在！");
            }
            try {
                id = Long.parseLong(Base64Util.aesDecoder(pId));
            } catch (Exception e) {
                logger.info("页面参数被恶意篡改，提示“对不起，您查看的页面不存在！”------"+pId);
                throw new BorrowException("对不起，您查看的页面不存在！");
            }
        }
        MovieConfig movie = movieConfigDao.find(id);
        if (StringUtil.isBlank(movie)) {
            request.setAttribute("priceFlag", 0);
        } else {
            request.setAttribute("priceFlag", 1);
        }
        request.setAttribute("movie", movie);
        request.setAttribute("buyMovieTicketsToken", buyMovieTicketsToken);
        return "ticket";
    }

    /**
     * 购买电影票
     * @throws Exception
     * if has error
     */
    @Action(value = "/movieTicket/buyMovieTickets",
            interceptorRefs = {@InterceptorRef("session"), @InterceptorRef("globalStack") },results =
            {@Result(name = "retResult", type = "ftl", location = "/retresult.html")})
    public String buyMovieTickets() throws Exception {

        // 重复提交校验
        checkToken("buyMovieTicketsToken");

        User user = userService.find(getSessionUserId());
        UserIdentify userIdentify = userIdentifyService.findByUserId(user.getUserId());

        String money = paramString("price");
        long id = paramLong("movieId");// 电影ID
        int moviePages = paramInt("number");// 电影张数
        String payPwd = paramString("pass");// 支付密码

        // 校验用户认证状态及用户类型
        checkUser(userIdentify, UserUtils.getUserCacheByUserId(user.getUserId()));
        // 电影票校验
        checkMovieTickets(money,payPwd,user,UserUtils.getUserCacheByUserId(user.getUserId()),id,moviePages);

        double actualPayMoney = BigDecimalUtil.round(Double.valueOf(money).doubleValue());// 支付金额

        String resultFlag = System.currentTimeMillis() + "" + Math.random() * 10000;
        // 购买电影票交由队列处理
        ConcurrentUtil.buyMovieTickets(user.getUserId(), actualPayMoney, id, moviePages, resultFlag);

        request.setAttribute("resultFlag", resultFlag);
        request.setAttribute("left_url", "/member/redpacket/availableRedEnvelope.html?tab=4"); // 成功返回地址
        request.setAttribute("right_url", "/member/main.html"); // 成功返回地址
        request.setAttribute("back_url", "/member/redpacket/availableRedEnvelope.html?tab=4"); // 成功返回地址
        request.setAttribute("left_msg", MessageUtil.getMessage("I10024"));
        request.setAttribute("right_msg", MessageUtil.getMessage("I10001"));
        request.setAttribute("r_msg", MessageUtil.getMessage("I10025"));
        return "retResult";
    }

    /**
     * 购票前校验用户认证状态及用户类型
     *
     * @param userIdentify
     */
    public void checkUser(UserIdentify userIdentify, UserCache userCache) {

        if (userIdentify.getRealNameStatus() == 0) {
            throw new UserException("请先实名认证", UserException.TYPE_CLOSE);
        }
    }

    public void checkMovieTickets(String money,String payPwd, User user, UserCache userCache,long id,int moviePages ) {

        // 返回地址
        String pId = "";
        try {
            pId = Base64Util.aesEncoder(id+"");
        } catch (Exception e) {
            e.printStackTrace();
        }
        String redirectUrl = "/movieTicket/ticket.html?id="+pId;

        if ("-".equals(money)) {
            throw new BorrowException("没有足够的票源，请稍后再试!", redirectUrl);
        }
        if (money.contains(".")) {
            String[] tem = money.split("\\.");
            if (tem[1].length() > 2) {
                throw new AccountException("金额最多只能保留两位小数！请联系客服。", redirectUrl);
            }
        }

        double actualPayMoney = BigDecimalUtil.round(Double.valueOf(money).doubleValue());// 支付金额

        AccountDao accountDao = (AccountDao) BeanUtil.getBean("accountDao");
        Account act = accountDao.findByUserId(user.getUserId());

        if (userCache.getStatus() == 1) {
            throw new BorrowException("您账号已经被锁定，不能进行购票!", redirectUrl);
        }
        // 实际支付金额
        if (actualPayMoney <= 0) {
            throw new BorrowException("实际支付金额不能少于1元!", redirectUrl);
        }

        MovieConfig movie = movieConfigDao.find(id);
        if (StringUtil.isBlank(movie)) {
            throw new BorrowException("没有足够的票源，请稍后再试", redirectUrl);
        }

        if (moviePages <= 0) {
            throw new BorrowException("购买数量超过允许范围", redirectUrl);
        }

        // 防止篡改
        // 单价
        double actualPrice = BigDecimalUtil.div(actualPayMoney, moviePages);
        if (movie.getPrice() != actualPrice) {
            throw new BorrowException("金额有误!", redirectUrl);
        }
        // 总额
        double realAmount = BigDecimalUtil.mul(movie.getPrice(),moviePages);
        if (actualPayMoney != realAmount) {
            throw new BorrowException("总额有误!", redirectUrl);
        }

        if (StringUtil.isBlank(payPwd)) {
            throw new BorrowException("交易密码不能为空!", redirectUrl);
        }

        if (!MD5.encode(payPwd).equals(user.getPayPwd())) {
            throw new BorrowException("交易密码不正确!", redirectUrl);
        }

        if (actualPayMoney > act.getUseMoney()) {
            throw new BorrowException("您的可用余额不足，请先充值！ ", redirectUrl);
        }

        // 第三方可用余额判断
        TppModel tppModel = new TppModel();
        tppModel.setUser(user);
        TppBaseInterface tppService = TppServiceFactory.newIntance();;
        TppAccountModel tppAccount = (TppAccountModel) tppService.tppQueryBalance(tppModel);
        if (actualPayMoney > Double.valueOf(tppAccount.getUserMoney()).doubleValue()) {
            throw new BorrowException("您的托管资金还存在未处理记录，请耐心等待！ ", redirectUrl);
        }
    }
}
